package com.autumn.mybatis.provider;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import com.autumn.mybatis.provider.mysql.MySqlProvider;
import com.autumn.mybatis.provider.sqlserver.SqlServerProvider;
import com.autumn.util.StringUtils;
import com.autumn.util.TypeUtils;

/**
 * 数据驱动类型 描述：
 * 
 * @author 杨昌国 2018-03-17 21:02:14
 */
public enum ProviderDriveType {

	/**
	 * MySql 数据库
	 */
	MYSQL(IDbProvider.CONNECT_TYPE_MY_SQL, MySqlProvider.class, "jdbc:mysql"),
	/**
	 * PostgresSql 数据库
	 */
	POSTGRESSQL(IDbProvider.CONNECT_TYPE_POSTGRESSQL, null, "jdbc:postgressql"),
	/**
	 * Oracle 数据库
	 */
	ORACLE(IDbProvider.CONNECT_TYPE_ORACLE, null, "jdbc:oracle"),
	/**
	 * Sql Server 数据库
	 */
	SQLSERVER(IDbProvider.CONNECT_TYPE_SQL_SERVER, SqlServerProvider.class, "jdbc:sqlserver"),
	/**
	 * DB2 数据库
	 */
	DB2(IDbProvider.CONNECT_TYPE_DB2, null, "jdbc:db2"),
	/**
	 * MariaDB 数据库
	 */
	MARIADB(IDbProvider.CONNECT_TYPE_MARIADB, null, "jdbc:mariadb"),
	/**
	 * Sybase 数据库
	 */
	SYBASE(IDbProvider.CONNECT_TYPE_SYBASE, null, "jdbc:sybase"),
	/**
	 * SQLite 数据库
	 */
	SQLITE(IDbProvider.CONNECT_TYPE_SQLITE, null, "jdbc:sqlite"),
	/**
	 * Access 连接类型
	 */
	ACCESS(IDbProvider.CONNECT_TYPE_ACCESS, null, "jdbc:odbc"),
	/**
	 * OceanBase 分布式关系数据库
	 */
	OCEANBASE(IDbProvider.CONNECT_TYPE_OCEANBASE, null, "jdbc:mysql"),

	/**
	 * 自定义或未知
	 */
	CUSTOM(IDbProvider.CONNECT_TYPE_CUSTOM, null, " ")

	;
	private final int connectType;
	private final Class<? extends IDbProvider> defaultProviderType;
	private final String urlPrefix;

	/**
	 * 获取连接类型
	 * 
	 * @return
	 */
	public int getConnectType() {
		return connectType;
	}

	/**
	 * 获取默认驱动类型
	 * 
	 * @return
	 */
	public Class<? extends IDbProvider> getDefaultProviderType() {
		return defaultProviderType;
	}

	/**
	 * 获取 Url 前缀
	 * 
	 * @return
	 */
	public String getUrlPrefix() {
		return urlPrefix;
	}

	private ProviderDriveType(int connectType, Class<? extends IDbProvider> defaultProviderType, String urlPrefix) {
		this.connectType = connectType;
		this.defaultProviderType = defaultProviderType;
		this.urlPrefix = urlPrefix;
	}

	private static final Map<ProviderDriveType, Set<String>> DATA_SOURCE_DRIVER_CLASS_MAP = new ConcurrentHashMap<>();

	static {
		addDriveType(ProviderDriveType.MYSQL, "com.mysql.jdbc.Driver");
		addDriveType(ProviderDriveType.POSTGRESSQL, "org.postgresql.Driver");
		addDriveType(ProviderDriveType.ORACLE, "oracle.jdbc.driver.OracleDriver");
		addDriveType(ProviderDriveType.SQLSERVER, "com.microsoft.sqlserver.jdbc.SQLServerDriver");
		addDriveType(ProviderDriveType.DB2, "com.ibm.db2.jcc.DB2Driver");
		addDriveType(ProviderDriveType.MARIADB, "com.mysql.jdbc.Driver");
		addDriveType(ProviderDriveType.SYBASE, "com.sybase.jdbc4.jdbc.SybDriver");
		addDriveType(ProviderDriveType.SQLITE, "org.sqlite.JDBC");
		addDriveType(ProviderDriveType.ACCESS, "sun.jdbc.odbc.JdbcOdbcDriver");
		addDriveType(ProviderDriveType.OCEANBASE, "com.mysql.jdbc.Driver");
	}

	private static void addDriveType(ProviderDriveType type, String... driveTypes) {
		Set<String> driverSet = new LinkedHashSet<>();
		if (driveTypes != null && driveTypes.length > 0) {
			for (String value : driveTypes) {
				if (!StringUtils.isNullOrBlank(value)) {
					driverSet.add(value);
				}
			}
		}
		DATA_SOURCE_DRIVER_CLASS_MAP.put(type, Collections.unmodifiableSet(driverSet));
	}

	/**
	 * 获取驱动类名称集合
	 * 
	 * @param type
	 *            类型
	 * @return
	 */
	public static Set<String> getDriverClassNameSet(ProviderDriveType type) {
		if (type == null) {
			return null;
		}
		return DATA_SOURCE_DRIVER_CLASS_MAP.get(type);
	}

	/**
	 * 获取首个已加载的驱动类名称
	 * 
	 * @param type
	 *            类型
	 * @return 不存在则返回 null
	 */
	public static String getFirstLoaderDriverClassName(ProviderDriveType type) {
		Set<String> types = getDriverClassNameSet(type);
		if (types == null || types.size() == 0) {
			return null;
		}
		for (String driveType : types) {
			if (TypeUtils.isExistClassName(driveType)) {
				return driveType;
			}
		}
		return null;
	}

	/**
	 * 根据连接类型获取获取驱动类型
	 * 
	 * @param connectType
	 *            值
	 * @return
	 */
	public static ProviderDriveType getDriveTypeForConnectType(int connectType) {
		for (ProviderDriveType type : ProviderDriveType.values()) {
			if (type.getConnectType() == connectType) {
				return type;
			}
		}
		return ProviderDriveType.CUSTOM;
	}

	/**
	 * 根据 Url 前缀获取驱动类型
	 * 
	 * @param url
	 *            url 前缀，如
	 *            jdbc:mysql://127.0.0.1:3306/ds1?characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
	 * @return
	 */
	public static ProviderDriveType getDriveTypeForUrlPrefix(String url) {
		if (StringUtils.isNullOrBlank(url)) {
			return ProviderDriveType.CUSTOM;
		}
		url = url.trim().toLowerCase();
		for (ProviderDriveType type : ProviderDriveType.values()) {
			if (url.startsWith(type.getUrlPrefix())) {
				return type;
			}
		}
		return ProviderDriveType.CUSTOM;
	}

}
